package com.stenio.fancat.service.shop;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.plugins.Page;
import com.stenio.fancat.domain.baby.BabyAccount;
import com.stenio.fancat.domain.shop.FcOrder;
import com.stenio.fancat.domain.shop.FcRedOrder;
import com.stenio.fancat.domain.shop.FcShop;
import com.stenio.fancat.domain.user.UserRelationship;
import com.stenio.fancat.domain.user.UserRelationshipFomId;
import com.stenio.fancat.domain.user.UserRelationshipLog;
import com.stenio.fancat.exception.FanCatException;
import com.stenio.fancat.form.shop.RedPacketOrderForm;
import com.stenio.fancat.form.shop.ShopOrderForm;
import com.stenio.fancat.mapper.baby.BabyAccountMapper;
import com.stenio.fancat.mapper.shop.FcRedOrderMapper;
import com.stenio.fancat.mapper.shop.FcShopMapper;
import com.stenio.fancat.mapper.user.UserRelationshipCandyMapper;
import com.stenio.fancat.mapper.user.UserRelationshipFomIdMapper;
import com.stenio.fancat.mapper.user.UserRelationshipLogMapper;
import com.stenio.fancat.mapper.user.UserRelationshipMapper;
import com.stenio.fancat.service.shop.CategoryService;
import com.stenio.fancat.service.wx.WxPushServiceQcl;
import com.stenio.fancat.util.DateUtil;
import com.stenio.fancat.util.StringUtil;
import com.stenio.fancat.util.XmlUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.security.KeyStore;
import java.text.ParseException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author liuan
 * @create 2019-01-30 14:47
 */
@Service
public class SendRedPacketService {

    @Value("${red.mch-id}")
    private String mch_id;

    @Value("${red.appid}")
    private String appid;

    @Value("${red.Addr}")
    private String Addr;

    @Value("${red.api_key}")
    private String api_key;

    @Autowired
    private FcRedOrderMapper fcRedOrderMapper;

    @Autowired
    private UserRelationshipMapper userRelationshipMapper;

    @Autowired
    private UserRelationshipLogMapper userRelationshipLogMapper;

    @Autowired
    private UserRelationshipCandyMapper userRelationshipCandyMapper;

    @Autowired
    private BabyAccountMapper babyAccountMapper;

    @Autowired
    private FcShopMapper fcShopMapper;

    @Autowired
    private WxPushServiceQcl wxPushServiceQcl;

    @Autowired
    private UserRelationshipFomIdMapper userRelationshipFomIdMapper;

    @Value("${templatePic_integral}")
    private String templatePicIntegral;

    private static final Logger logger = LoggerFactory.getLogger(CategoryService.class);


    /**
     * 根据订单号查询订单详情
     * @param id
     * @return
     */
    public FcRedOrder getById(String id) {
        return fcRedOrderMapper.selectById(id);
    }


    /**
     * 根据条件查询
     * @param redPacketOrderForm
     * @return
     */
    public Page<FcRedOrder> selectByPage(RedPacketOrderForm redPacketOrderForm){
        FcRedOrder fcRedOrder = new FcRedOrder();
        BeanUtils.copyProperties(redPacketOrderForm,fcRedOrder);
        Page<FcRedOrder> page = new Page<>(redPacketOrderForm.getPageNo(), redPacketOrderForm.getPageSize());
        page.setRecords(fcRedOrderMapper.selectByConditionPage(page,fcRedOrder));
        return page;
    }

    /**
     * 根据用户id查询红包订单方法
     * @param id
     * @return
     */
    public List<FcRedOrder> selectRedOrder(String id) {
        return fcRedOrderMapper.selectRedOrder(id);
    }

    /**
     * 添加红包订单方法
     * @param fcRedOrder
     * @return
     * @throws FanCatException
     */
    @Transactional
    public FcRedOrder insert(FcRedOrder fcRedOrder) throws FanCatException {
        FcShop fcShop = fcShopMapper.selectById(fcRedOrder.getBusinessId());
        if (fcShop.getStock() <= 0) {
            throw new FanCatException("库存不足");
        }
        UserRelationship userRelationship = userRelationshipMapper.selectUserInfoById(fcRedOrder.getUserId());
        BabyAccount babyAccount = babyAccountMapper.selectById(userRelationship.getBabyId());
        if(babyAccount.getSurplusCandy() < fcRedOrder.getOrderPrice()) {
            throw new FanCatException("糖果币余额不足");
        }

        //处理发送逻辑
        boolean flag = true;
        if(fcShop.getSendType() == 3) {
            //根据baby查询所有相关user
            List<UserRelationship> userRelationships = userRelationshipMapper.selectRelationship(userRelationship.getBabyId());
            for (UserRelationship relationship : userRelationships) {
                List<FcRedOrder> fcRedOrders = fcRedOrderMapper.selectRedOrderByUAndB(relationship.getUserId(),fcRedOrder.getBusinessId());
                if(CollectionUtils.isNotEmpty(fcRedOrders)) {
                    throw new FanCatException("状态3描述");
                }
            }
        }else if(fcShop.getSendType() == 2) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            LocalDateTime now = LocalDateTime.now();
            String day = now.format(formatter);
            List<UserRelationship> userRelationships = userRelationshipMapper.selectRelationship(userRelationship.getBabyId());
            for (UserRelationship relationship : userRelationships) {
                List<FcRedOrder> fcRedOrders = fcRedOrderMapper.selectRedOrderByUAndB(relationship.getUserId(),fcRedOrder.getBusinessId());
                if(CollectionUtils.isNotEmpty(fcRedOrders)) {
                    for (FcRedOrder redOrder : fcRedOrders) {
                        LocalDateTime orderDay = LocalDateTime.ofInstant(redOrder.getCreateTime().toInstant(), ZoneId.systemDefault());
                        if(day.equals(orderDay.format(formatter))) {
                            throw new FanCatException("状态2描述");
                        }
                    }
                }
            }
        }
        //执行发送
        if(flag){
            Integer money = (int)(fcShop.getMoney()*100);
            String currTime = DateUtil.getCurrTime();
            String strRandom = StringUtil.buildRandom(4)+"";
            String id = currTime + strRandom;
            Date date = new Date();
            fcRedOrder.setCreateTime(date);
            fcRedOrder.setUpdateTime(date);
            fcRedOrder.setId(id);
            fcRedOrder.setOrderId(id);
            fcRedOrder.setOrderStatus(1);
            fcRedOrder.setOrderType(3);
            int i = fcRedOrderMapper.insertRedOrder(fcRedOrder);
            if(i>0) {
                Map<String, String> resultMap = sendWallet(userRelationship.getOpenId(),money,fcShop.getName());
                if(resultMap.isEmpty()) {
                    throw new FanCatException("红包订单发送失败");
                }
                fcRedOrder.setPaymentNo(resultMap.get("payment_no"));
                fcRedOrder.setPartnerTradeNo(resultMap.get("partner_trade_no"));
                fcRedOrder.setOrderStatus(2);
                try {
                    fcRedOrder.setSendTime(DateUtil.parse(resultMap.get("payment_time"),"yyyy-MM-dd HH:mm:ss"));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                fcRedOrderMapper.updateRedOrder(fcRedOrder);
                //更新库存
                fcShopMapper.updateStock(fcRedOrder.getBusinessId(),1,1);
                //更新个人总金额增-减记录
                userRelationshipCandyMapper.updateReduceCandyById(fcRedOrder.getUserId(),fcRedOrder.getOrderPrice());
                //更新baby金额
                babyAccount.setSurplusCandy(babyAccount.getSurplusCandy()-fcRedOrder.getOrderPrice());
                babyAccountMapper.updateById(babyAccount);
                //新增个人消费记录
                UserRelationshipLog u = new UserRelationshipLog();
                u.setUserId(fcRedOrder.getUserId());
                u.setOperType(2);
                u.setCandy(fcRedOrder.getOrderPrice());
                u.setBeforeCandy(babyAccount.getSurplusCandy());
                u.setAfterCandy(babyAccount.getSurplusCandy()-fcRedOrder.getOrderPrice());
                userRelationshipLogMapper.insert(u);
                String format =  DateUtil.format(date, "yyyy-MM-dd");
                String[] keys = {id,fcShop.getName(),format,fcRedOrder.getOrderPrice().toString(),(babyAccount.getSurplusCandy()-fcRedOrder.getOrderPrice())+""};
                UserRelationshipFomId userRelationshipFomId = userRelationshipFomIdMapper.selectFormIdByUid(fcRedOrder.getUserId());
                if(userRelationshipFomId != null) {
                    wxPushServiceQcl.pushOneUser(userRelationship.getOpenId(),
                            userRelationshipFomId.getFormId(),
                            templatePicIntegral,
                            keys);
                    userRelationshipFomIdMapper.modifyFormIdByUid(fcRedOrder.getUserId(),userRelationshipFomId.getFormId());
                }


            }

        }

        return fcRedOrder;
    }

    /**
     * 发送微信红包
     * @param openId
     * @return
     */
    public String sendRedPacket(String openId,Integer redValue) {
        SortedMap<Object,Object> parameters = new TreeMap<>();
        String currTime = DateUtil.getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom = StringUtil.buildRandom(4)+"";
        //随机字符串
        parameters.put("nonce_str", StringUtil.getNonceStr());
        //商户订单号
        parameters.put("mch_billno",strTime + strRandom);
        //商户号
        parameters.put("mch_id",mch_id);
        //公众号appid
        parameters.put("wxappid",appid);
        //商户名称
        parameters.put("send_name","图米云");
        //用户openid
        parameters.put("re_openid",openId);
        //付款金额
        parameters.put("total_amount",redValue);
        //红包发放总人数
        parameters.put("total_num",1);
        //红包祝福语
        parameters.put("wishing","红包祝福语");
        //ip地址
        parameters.put("client_ip",Addr);
        //活动名称
        parameters.put("act_name","活动名称");
        //备注
        parameters.put("remark","备注");
        //签名
        parameters.put("sign",createSign(parameters,api_key));
        String requestXml = XmlUtil.getRequestXml(parameters);
        CloseableHttpClient httpClient = null;
        Map<String,String> result = new HashMap<>();
        try {
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            String pathname = "/root/fancatV1.0/red_certificate/apiclient_cert.p12";
            FileInputStream inputStream = new FileInputStream(new File(pathname));
            try {
                keyStore.load(inputStream,mch_id.toCharArray());
            } finally {
                inputStream.close();
            }
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    new String[]{"TLSv1"},
                    null,
                    SSLConnectionSocketFactory.getDefaultHostnameVerifier());
            httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        } catch (Exception e) {
            logger.info("读取证书信息错误：" + e.getMessage());
            e.printStackTrace();
        }
        try {
            String requestUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
            HttpPost httpPost = new HttpPost(requestUrl);
            StringEntity reqEntity  = new StringEntity(requestXml, "utf-8");
            reqEntity.setContentType("application/x-www-form-urlencoded");
            httpPost.setEntity(reqEntity);
            CloseableHttpResponse response = httpClient.execute(httpPost);
            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    // 从request中取得输入流
                    InputStream inputStream = entity.getContent();
                    // 读取输入流
                    SAXReader reader = new SAXReader();
                    Document document = reader.read(inputStream);
                    // 得到xml根元素
                    Element root = document.getRootElement();
                    // 得到根元素的所有子节点
                    List<Element> elementList = root.elements();
                    // 遍历所有子节点
                    for (Element e : elementList)
                    {
                        result.put(e.getName(), e.getText());
                    }
                    // 释放资源
                    inputStream.close();
                }
                EntityUtils.consume(entity);
            }finally {
                if(response != null) {
                    response.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        logger.info("------------------发送红包结束---------------");
        logger.info("发送红包微信返回的信息是："+ JSON.toJSONString(result));
        //假如发送成功的话，保存发送的信息
        if(result.get("return_msg").equals("发放成功")) {
            logger.info("红包发放成功openid="+openId+",发送时间是："+DateUtil.getPreDay(new Date(),0));
            return "1";
        } else {
            logger.info("红包发放失败，openid="+openId+",发送时间是："+DateUtil.getPreDay(new Date(),0));
            return "2";
        }
    }

    /**
     * 企业付款到零钱
     * @param openId
     * @return
     */
    public Map<String, String> sendWallet(String openId,Integer redValue, String desc) {
        //创建一个唯一订单号
        String currTime = DateUtil.getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom = StringUtil.buildRandom(4) + "";
        String orderId = strTime + strRandom;
        String xml = wxSendWallet(orderId, openId, String.valueOf(redValue), desc);
        Map<String,String> resultMap = new HashMap<>();
        try {
            //指定读取证书格式为PKCS12
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            //linux系统,读取本机存放的PKCS12证书文件
            String pathname = "/root/fancatV1.0/red_certificate/apiclient_cert.p12";
            FileInputStream instream = new FileInputStream(new File(pathname));
            try {
                //指定PKCS12的密码(商户ID)
                keyStore.load(instream, mch_id.toCharArray());
            } finally {
                instream.close();
            }
            // Trust own CA and all self-signed certs
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
            //指定TLS版本, Allow TLSv1 protocol only
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
            //设置httpclient的SSLSocketFactory
            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
            HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
            //这里要设置编码，不然xml中有中文的话会提示签名失败或者展示乱码
            httppost.addHeader("Content-Type", "text/xml");
            StringEntity se = new StringEntity(xml, "UTF-8");
            httppost.setEntity(se);
            CloseableHttpResponse responseEntry = httpclient.execute(httppost);
            try {
                HttpEntity entity = responseEntry.getEntity();
                if (entity != null) {
                    System.out.println("响应内容长度 : " + entity.getContentLength());
                    SAXReader saxReader = new SAXReader();
                    Document document = saxReader.read(entity.getContent());
                    Element rootElt = document.getRootElement();
                    String resultCode = rootElt.elementText("result_code");
                    if (resultCode.equals("SUCCESS")) {
                        //保存红包信息到数据库
                        //保存用户领取记录
                        resultMap.put("partner_trade_no",rootElt.elementText("partner_trade_no"));
                        resultMap.put("payment_no",rootElt.elementText("payment_no"));
                        resultMap.put("payment_time",rootElt.elementText("payment_time"));
                    } else {
                        logger.info(rootElt.elementText("err_code_des"));
                    }
                }
                EntityUtils.consume(entity);
            } catch (Exception e) {
                logger.info("请求失败");
            } finally {
                responseEntry.close();
            }
        } catch (Exception e) {
            logger.info("请求失败");
        }
        return resultMap;
    }

    /**
     * 红包创建签名方法
     * @param parameters
     * @param api_key
     * @return
     */
    public String createSign(SortedMap<Object, Object> parameters,String api_key){
        StringBuffer sb = new StringBuffer();
        Set<Map.Entry<Object, Object>> es = parameters.entrySet();
        Iterator<Map.Entry<Object, Object>> it = es.iterator();
        while (it.hasNext()) {
            Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            /** 如果参数为key或者sign，则不参与加密签名 */
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        System.out.println("传过来的支付密钥api_key="+api_key);
        /** 支付密钥必须参与加密，放在字符串最后面 */
        sb.append("key=" + api_key);
        /** 记得最后一定要转换为大写 */
        String sign = StringUtil.md5(sb.toString()).toUpperCase();
        return sign;
    }


    /**
     * 零钱拼接xml
     * @param partner_trade_no
     * @param openid
     * @param total_amount
     * @return
     */
    public String wxSendWallet(String partner_trade_no, String openid,String total_amount,String desc) {
        String data = null;
        try {
            String nonceStr = StringUtil.getNonceStr();
            //SortedMap接口主要提供有序的Map实现，默认的排序是根据key值进行升序排序
            SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();
            parameters.put("mch_appid", appid);
            parameters.put("mchid", mch_id);
            parameters.put("nonce_str", nonceStr);
            parameters.put("partner_trade_no", partner_trade_no);
            parameters.put("openid", openid);
            parameters.put("check_name", "NO_CHECK");
            parameters.put("amount", total_amount);
            parameters.put("spbill_create_ip", Addr);
            parameters.put("desc", desc);
            //签名
            parameters.put("sign", createSign2(parameters, api_key));
            data =XmlUtil.getRequestXml(parameters);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 零钱生成签名方法
     * @param packageParams
     * @param AppKey
     * @return
     */
    public static String createSign2(SortedMap<Object, Object> packageParams, String AppKey) {
        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + AppKey);
        String sign = StringUtil.md5(sb.toString()).toUpperCase();
        return sign;
    }

}
